import allure
from selenium.common import TimeoutException
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.ui import WebDriverWait
from common.logger import log
from selenium.webdriver.common.by import By
from typing import Tuple, Optional


class BasePage(object):
    def __init__(self, driver):
        #初始化浏览器驱动
        self.driver = driver
        #用于缓存标签页对象
        self.page_cache = {}

    @allure.step("鼠标左键点击")
    def l_click(self, locator: Tuple[str, str], note: str = '', timeout: int = 10) -> bool:
        """
        driver为浏览器驱动实例
        locator为元素定位
        note为备注，用于日志排查，默认为空
        timeout为显示等待时间，默认10s
        Selenium 左键点击操作
        """
        try:
            #等待可点击后，点击
            WebDriverWait(self.driver, timeout).until(expected_conditions.element_to_be_clickable(locator)).click()
            log.debug(f"{locator}点击成功"+note)
            return True
        except Exception as click_error:
            log.error(f"无法定位到元素{locator}, 异常为 {click_error}"+note)


    @allure.step("输入内容")
    def send_keys(self, locator: Tuple[str, str], value: str, note: str = '', timeout: int = 10) -> bool:
        """
        driver为浏览器驱动实例
        locator为元素定位
        value为输入值
        note为备注，用于日志排查，默认为空
        timeout为显示等待时间，默认10s
        Selenium 输入操作
        """
        try:
            #等待可点击后，清除输入框内容
            element = WebDriverWait(self.driver, timeout).until(expected_conditions.element_to_be_clickable(locator))
            element.clear()#等待可点击后，向输入框输入内容
            element.send_keys(value)#输入需要输入内容
            log.debug(f"向{locator}，输入{value}"+note)
            return True
        except Exception as input_error:
            log.error(f"无法定位元素，{locator}, 异常为 {input_error}"+note)



    @allure.step("获取文本内容")
    def get_text(self, locator: Tuple[str, str], note: str = '', timeout: int = 10) -> Optional[str]:
        """
        driver为浏览器驱动实例
        locator为元素定位
        note为备注，用于日志排查，默认为空
        timeout为显示等待时间，默认10s
        Selenium 左键点击操作
        """
        try:
            #判断元素出现在dom树中后，获取元素文本
            element = WebDriverWait(self.driver, timeout).until(expected_conditions.presence_of_element_located(locator))
            log.debug("获取到文本:"+element.text+note)
            return element.text
        except Exception as text_error:
            log.error(f"文本提取错误，{text_error}"+note)
            return None

    @allure.step("切换标签页")
    def switch_to_tab(self, tab_num: int) -> Optional[str]:
        """
        :param tab_num:想要切换的标签页句柄号数
        :return:返回焦点页的tittle
        还可以添加等待保证切换完成
        """
        try:
            window_handle = self.driver.window_handles
            log.debug("获取句柄成功")
            if tab_num < len(window_handle):
                self.driver.switch_to.window(window_handle[tab_num])
                log.debug(f"切换到的标签页title为{self.driver.title}")
                return self.driver.title
            else:
                log.error("输入的句柄数超出限制")
                raise IndexError
        except Exception as switch_tab_error:
            log.error(f"切换浏览器标签页错误，错误信息{switch_tab_error}")

    @allure.step("获取元素属性内容")
    def get_att(self, locator: Tuple[str, str], attname:str,timeout: int = 10) -> Optional[str]:
        """
        :param locator: 定位器
        :param attname: 所查找元素内容
        :param timeout: 等待时间
        :return:
        """
        try:
            content = WebDriverWait(self.driver, timeout).until(expected_conditions.presence_of_element_located(locator)).get_attribute(attname)
            log.debug(f"获取元素：{locator},的属性：{attname}的值：{content}成功")
            return content
        except Exception as get_att_error:
            log.error(f"获取元素属性：{attname}内容错误，错误为：{get_att_error}")

    @allure.step("打开网页")
    def open_url(self,url:str,timeout: int = 10) -> bool:
        """
        :param url: 网页地址
        :param timeout: 等待时间
        :return: 是否打开成功的布尔值
        """
        try:
            # 尝试打开URL
            log.debug(f"正在打开网址: {url}")
            self.driver.get(url)

            # 显式等待，直到页面完全加载或等待超时
            WebDriverWait(self.driver, timeout).until(
                lambda driver: driver.execute_script("return document.readyState") == "complete"
            )
            log.info(f"成功打开网址: {url}")
            return True
        except Exception as open_url_error:
            log.error(f"打开网址 {url} 时出错，错误信息: {open_url_error}")
            return False

    @allure.step("换取当前页面的页面对象")
    def get_page_object(self,page_class)->object:
        """
        :param page_class: 页面对象类
        :return:页面对象
        """
        try:
            #判断是否有缓存，无缓存添加缓存
            if page_class not in self.page_cache:
                self.page_cache[page_class] = page_class(self.driver)
                log.debug("当前页面对象未缓存，缓存成功")
            log.debug("获取当前页面对象成功")
            return self.page_cache[page_class]
        except TypeError  as get_page_object_error_type:
            log.error(f"获取页面对象错误，类型错误{get_page_object_error_type}")
            raise get_page_object_error_type
        except Exception as get_page_object_error_unknown:
            log.error(f"获取页面对象失败，未知错误{get_page_object_error_unknown}")
            raise get_page_object_error_unknown

    @allure.step("等待3秒，当前url是否为期望url")
    def is_expected_url(self,excepted_url):
        try:
            WebDriverWait(self.driver, 3).until(expected_conditions.url_changes(self.driver.current_url))
            log.debug("url发生变化")
            return self.driver.current_url == excepted_url
        except TimeoutException:
            log.debug("url未发生变化")
            return self.driver.current_url == excepted_url
        except Exception as is_expected_url_error:
            log.error(f"判断url为期望url发生未知错误：{is_expected_url_error}")
            raise is_expected_url_error
















